1500 // Mutual exclusion spin locks.
1501 
1502 #include "types.h"
1503 #include "defs.h"
1504 #include "param.h"
1505 #include "x86.h"
1506 #include "mmu.h"
1507 #include "proc.h"
1508 #include "spinlock.h"
1509 
1510 void
1511 initlock(struct spinlock *lk, char *name)
1512 {
1513   lk->name = name;
1514   lk->locked = 0;
1515   lk->cpu = 0;
1516 }
1517 
1518 // Acquire the lock.
1519 // Loops (spins) until the lock is acquired.
1520 // Holding a lock for a long time may cause
1521 // other CPUs to waste time spinning to acquire it.
1522 void
1523 acquire(struct spinlock *lk)
1524 {
1525   pushcli();
1526   if(holding(lk))
1527     panic("acquire");
1528 
1529   // The xchg is atomic.
1530   // It also serializes, so that reads after acquire are not
1531   // reordered before it.
1532   while(xchg(&lk->locked, 1) != 0)
1533     ;
1534 
1535   // Record info about lock acquisition for debugging.
1536   lk->cpu = cpu;
1537   getcallerpcs(&lk, lk->pcs);
1538 }
1539 
1540 
1541 
1542 
1543 
1544 
1545 
1546 
1547 
1548 
1549 
1550 // Release the lock.
1551 void
1552 release(struct spinlock *lk)
1553 {
1554   if(!holding(lk))
1555     panic("release");
1556 
1557   lk->pcs[0] = 0;
1558   lk->cpu = 0;
1559 
1560   // The xchg serializes, so that reads before release are
1561   // not reordered after it.  The 1996 PentiumPro manual (Volume 3,
1562   // 7.2) says reads can be carried out speculatively and in
1563   // any order, which implies we need to serialize here.
1564   // But the 2007 Intel 64 Architecture Memory Ordering White
1565   // Paper says that Intel 64 and IA-32 will not move a load
1566   // after a store. So lock->locked = 0 would work here.
1567   // The xchg being asm volatile ensures gcc emits it after
1568   // the above assignments (and after the critical section).
1569   xchg(&lk->locked, 0);
1570 
1571   popcli();
1572 }
1573 
1574 // Record the current call stack in pcs[] by following the %ebp chain.
1575 void
1576 getcallerpcs(void *v, uint pcs[])
1577 {
1578   uint *ebp;
1579   int i;
1580 
1581   ebp = (uint*)v - 2;
1582   for(i = 0; i < 10; i++){
1583     if(ebp == 0 || ebp < (uint *) 0x100000 || ebp == (uint*)0xffffffff)
1584       break;
1585     pcs[i] = ebp[1];     // saved %eip
1586     ebp = (uint*)ebp[0]; // saved %ebp
1587   }
1588   for(; i < 10; i++)
1589     pcs[i] = 0;
1590 }
1591 
1592 // Check whether this cpu is holding the lock.
1593 int
1594 holding(struct spinlock *lock)
1595 {
1596   return lock->locked && lock->cpu == cpu;
1597 }
1598 
1599 
1600 // Pushcli/popcli are like cli/sti except that they are matched:
1601 // it takes two popcli to undo two pushcli.  Also, if interrupts
1602 // are off, then pushcli, popcli leaves them off.
1603 
1604 void
1605 pushcli(void)
1606 {
1607   int eflags;
1608 
1609   eflags = readeflags();
1610   cli();
1611   if(cpu->ncli++ == 0)
1612     cpu->intena = eflags & FL_IF;
1613 }
1614 
1615 void
1616 popcli(void)
1617 {
1618   if(readeflags()&FL_IF)
1619     panic("popcli - interruptible");
1620   if(--cpu->ncli < 0)
1621     panic("popcli");
1622   if(cpu->ncli == 0 && cpu->intena)
1623     sti();
1624 }
1625 
1626 
1627 
1628 
1629 
1630 
1631 
1632 
1633 
1634 
1635 
1636 
1637 
1638 
1639 
1640 
1641 
1642 
1643 
1644 
1645 
1646 
1647 
1648 
1649 
